<?php
/**
 * @author Vincent
 * @desc 导出CSV
 */

namespace young;

class ExportCsv
{
    private $temp_dir = './csv/';
    private $console = true;

    public function setTempDir($path)
    {
        $this->temp_dir = $path;
    }

    public function setConsole($value = false)
    {
        $this->console = $value;
    }

    public function factory(&$data, $callback)
    {
        if (substr($this->temp_dir, -1) !== '/') {
            $this->temp_dir .= '/';
        }
        if (!is_dir($this->temp_dir)) {
            mkdir($this->temp_dir);
        }
        $data['pages'] = intval(ceil($data['count'] / $data['pageSize']));//总页数
        $data['fileNameArray'] = [];//分页文件数组
        $data['key'] = md5(rand(100000, 999999));
        $data['time'] = date('YmdHis');

        $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 正在生成临时文件...请稍候</div>');

        if ($data['pages'] > 1) {
            $data['zipName'] = $this->temp_dir . $data['time'] . '_' . $data['key'] . '_' . $data['saveName'] . '.zip';
            for ($page = 1; $page <= $data['pages']; $page++) {
                $rows = $callback($data, $page);
                $this->exportCsv($data, $rows, $page);
            }
            $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 生成临时文件完成</div>');
            $this->createCsvZip($data);
            $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 删除临时文件</div>');
            $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 开始下载...</div>');
            $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 删除临时压缩包</div>');
            $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 导出完成</div>');

            $data['downloadUrl'] = url('public/downloadCsv', '', false, true) . '?_t=zip&_f=' . Common::string_encode($data['zipName'], $data['key']) . '&_k=' . $data['key'];
        } else {
            $rows = $callback($data, 1);
            $this->exportCsv($data, $rows, 0);
            $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 生成临时文件完成</div>');
            $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 删除临时文件</div>');
            $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 开始下载...</div>');
            $data['downloadUrl'] = url('public/downloadCsv', '', false, true) . '?_t=csv&_f=' . Common::string_encode($data['csvName'], $data['key']) . '&_k=' . $data['key'];
        }
    }

    public function outputToView($msg)
    {
        if ($this->console === true) {
            echo $msg;
            ob_flush();
            flush();
        }
    }

    private function exportCsv(&$data, $rows, $batch)
    {
        if ($batch > 0) {
            $name = $data['time'] . $data['key'] . '_' . $batch . '.csv';
            $filename = $this->temp_dir . $name; //设置文件名
            $data['fileNameArray'][] = $filename;
        } else {
            $filename = $this->temp_dir . $data['time'] . '_' . $data['key'] . '_' . $data['saveName'] . '.csv'; //设置文件名
            $data['csvName'] = $filename;
        }
        $fp = fopen($filename, 'w');
        foreach ($data['head'] as $k => $val) {
            $data['head'][$k] = iconv('utf-8', 'gb2312', $data['head'][$k]);
        }
        fputcsv($fp, $data['head']);
        foreach ($rows as $key => $value) {
            foreach ($value as $k => $val) {
                $value[$k] = iconv('utf-8', 'gb2312', $value[$k]);
            }
            fputcsv($fp, $value);
        }
        fclose($fp);
    }

    private function createCsvZip(&$data)
    {
        $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 开始压缩文件...</div>');
        $zip = new \ZipArchive();
        $zip->open($data['zipName'], \ZipArchive::CREATE);   //打开压缩包
        foreach ($data['fileNameArray'] as $file) {
            $zip->addFile($file, basename($file));   //向压缩包中添加文件
        }
        $zip->close();  //关闭压缩包
        foreach ($data['fileNameArray'] as $file) {
            @unlink($file); //删除csv临时文件
        }
        $this->outputToView('<div style="font-size:12px;color:green">' . date('H:i:s') . ' => 压缩文件完成</div>');
    }

    public function download($filename, $type)
    {
        switch ($type) {
            case 'csv':
                $this->downloadCsv($filename);
                break;
            case 'zip':
                $this->downloadCsvZip($filename);
                break;
        }
    }

    private function downloadCsv($fileName)
    {
        header("Cache-Control: max-age=0");
        header("Content-Description: File Transfer");
        header('Content-disposition: attachment; filename=' . basename($fileName));
        header("Content-Type: text/csv");
        header("Content-Transfer-Encoding: binary");
        header('Content-Length: ' . filesize($fileName));
        @readfile($fileName);
        @unlink($fileName);
    }

    private function downloadCsvZip($fileName)
    {
        header("Cache-Control: max-age=0");
        header("Content-Description: File Transfer");
        header('Content-disposition: attachment; filename=' . basename($fileName));
        header("Content-Type: application/zip");
        header("Content-Transfer-Encoding: binary");
        header('Content-Length: ' . filesize($fileName));
        @readfile($fileName);
        @unlink($fileName);
    }
}